From 712e1ef44106ccf3f353fe09c4bb23524c2de09d Mon Sep 17 00:00:00 2001 From: oliskoli Date: Wed, 5 Apr 2006 17:44:38 +0000 Subject: [PATCH] Bring in support for Garmin special data (garmin_fs). --- gpsbabel/defs.h | 6 + gpsbabel/garmin_fs.c | 254 +++++++++++++++++++++++++++++++++++++++++++ gpsbabel/garmin_fs.h | 120 ++++++++++++++++++++ 3 files changed, 380 insertions(+) create mode 100644 gpsbabel/garmin_fs.c create mode 100644 gpsbabel/garmin_fs.h diff --git a/gpsbabel/defs.h b/gpsbabel/defs.h index 0260ece12..85331995d 100644 --- a/gpsbabel/defs.h +++ b/gpsbabel/defs.h @@ -29,6 +29,7 @@ #include "gbtypes.h" #include "cet.h" #include "cet_util.h" +#include "inifile.h" /* @@ -119,6 +120,7 @@ typedef struct { int no_smart_names; cet_cs_vec_t *charset; char *charset_name; + inifile_t *inifile; } global_options; extern global_options global_opts; @@ -218,6 +220,7 @@ fs_xml *fs_xml_alloc( long type ); #define FS_AN1L 0x616e316cL #define FS_AN1V 0x616e3176L #define FS_OZI 0x6f7a6900L +#define FS_GMSD 0x474d5344L /* GMSD = Garmin specific data */ /* * Misc bitfields inside struct waypoint; @@ -320,6 +323,7 @@ typedef struct { queue waypoint_list; /* List of child waypoints */ char *rte_name; char *rte_desc; + char *rte_url; int rte_num; int rte_waypt_ct; /* # waypoints in waypoint list */ format_specific_data *fs; @@ -555,6 +559,8 @@ void is_fatal(const int condition, const char *, ...) PRINTFLIKE(2, 3); void warning(const char *, ...) PRINTFLIKE(1, 2); ff_vecs_t *find_vec(char * const, char **); +void assign_vec_option(const char *vecname, arglist_t *ap, const char *val); +void disp_vec_options(const char *vecname, arglist_t *ap); void disp_vecs(void); void exit_vecs(void); void disp_formats(int version); diff --git a/gpsbabel/garmin_fs.c b/gpsbabel/garmin_fs.c new file mode 100644 index 000000000..14c4f4744 --- /dev/null +++ b/gpsbabel/garmin_fs.c @@ -0,0 +1,254 @@ +/* + + Implementation of special data used by Garmin products. + + Copyright (C) 2006 Olaf Klein, o.b.klein@t-online.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "garmin_fs.h" +#include "garmin_tables.h" +#include "inifile.h" + +#define MYNAME "garmin_fs" + +garmin_fs_t * +garmin_fs_alloc(const int protocol) +{ + garmin_fs_t *result = NULL; + + result = (garmin_fs_t *)xcalloc(1, sizeof(*result)); + result->fs.type = FS_GMSD; + result->fs.copy = (fs_copy) garmin_fs_copy; + result->fs.destroy = garmin_fs_destroy; + result->fs.next = NULL; + + result->protocol = protocol; + + return result; +} + +void +garmin_fs_destroy(void *fs) +{ + garmin_fs_t *data = (garmin_fs_t *) fs; + if (data != NULL) + { + garmin_ilink_t *ilinks; + + if (data->city != NULL) xfree(data->city); + if (data->facility != NULL) xfree(data->facility); + if (data->state != NULL) xfree(data->state); + if (data->cc != NULL) xfree(data->cc); + if (data->cross_road != NULL) xfree(data->cross_road); + if ((ilinks = data->ilinks) != NULL) { + ilinks->ref_count--; + if (ilinks->ref_count <= 0) { + while (ilinks != NULL) { + garmin_ilink_t *tmp = ilinks; + ilinks = ilinks->next; + xfree(tmp); + } + } + } + xfree(data); + } +} + +void garmin_fs_copy(garmin_fs_t **dest, garmin_fs_t *src) +{ + if (src == NULL) + { + *dest = NULL; + return; + } + *dest = (garmin_fs_t *) xmalloc(sizeof(*src)); + + /* do not copy interlinks, only increment the refrence counter */ + if (src->ilinks != NULL) src->ilinks->ref_count++; + + memcpy(*dest, src, sizeof(*src)); + + (*dest)->city = (src->city != NULL) ? xstrdup(src->city) : NULL; + (*dest)->facility = (src->facility != NULL) ? xstrdup(src->facility) : NULL; + (*dest)->state = (src->state != NULL) ? xstrdup(src->facility) : NULL; + (*dest)->cc = (src->cc != NULL) ? xstrdup(src->cc) : NULL; + (*dest)->cross_road = (src->cross_road != NULL) ? xstrdup(src->cross_road) : NULL; + (*dest)->addr = (src->addr != NULL) ? xstrdup(src->addr) : NULL; +} + +/* GPX - out */ + +void +garmin_fs_xml_fprint(FILE *ofd, const waypoint *waypt) +{ + garmin_fs_t *gmsd = GMSD_FIND(waypt); + if (gmsd == NULL) return; + + if ((gmsd->flags.category && gmsd->category) || + gmsd->flags.depth || + gmsd->flags.proximity || + gmsd->flags.temperature || + gmsd->flags.display) + { + int space = 1; + + fprintf(ofd, "%*s\n", space++ * 2, ""); + fprintf(ofd, "%*s\n", space++ * 2, ""); + if (gmsd->flags.proximity) + fprintf(ofd, "%*s%.6f\n", space * 2, "", gmsd->proximity); + if (gmsd->flags.temperature) + fprintf(ofd, "%*s%.6f\n", space * 2, "", gmsd->temperature); + if (gmsd->flags.depth) + fprintf(ofd, "%*s%.6f\n", space * 2, "", gmsd->depth); + if (gmsd->flags.display) + { + char *cx; + switch(gmsd->display) + { + case gt_display_mode_symbol: + cx = "SymbolOnly"; + break; + case gt_display_mode_symbol_and_comment: + cx = "SymbolAndDescription"; + break; + default: + cx = "SymbolAndName"; + break; + } + fprintf(ofd, "%*s%s\n", space * 2, "", cx); + } + if (gmsd->flags.category && gmsd->category) + { + int i; + gbuint16 cx = gmsd->category; + fprintf(ofd, "%*s\n", space++ * 2, ""); + for (i = 0; i < 16; i++) + { + if (cx & 1) + fprintf(ofd, "%*sCategory %d\n", space*2, "", i+1); + cx = cx >> 1; + } + fprintf(ofd, "%*s\n", --space * 2, ""); + } + fprintf(ofd, "%*s\n", --space * 2, ""); + fprintf(ofd, "%*s\n", --space * 2, ""); + } + +} + +void +garmin_fs_xml_convert(const int base_tag, int tag, const char *cdatastr, waypoint *waypt) +{ + garmin_fs_t *gmsd; + + gmsd = GMSD_FIND(waypt); + if (gmsd == NULL) { + gmsd = garmin_fs_alloc(-1); + fs_chain_add(&waypt->fs, (format_specific_data *) gmsd); + } + + tag -= base_tag; +/* + tt_garmin_extension, -> 0 + tt_garmin_waypt_extension, -> 1 + tt_garmin_proximity, -> 2 + tt_garmin_temperature,-> 3 + tt_garmin_depth, -> 4 + tt_garmin_display_mode, -> 5 + tt_garmin_categories, -> 6 + tt_garmin_category, -> 7 +*/ + switch(tag) { + case 2: GMSD_SET(proximity, atof(cdatastr)); break; + case 3: GMSD_SET(temperature, atof(cdatastr)); break; + case 4: GMSD_SET(depth, atof(cdatastr)); break; + case 5: if (case_ignore_strcmp(cdatastr, "SymbolOnly") == 0) { + GMSD_SET(display, gt_display_mode_symbol); + } + else if (case_ignore_strcmp(cdatastr, "SymbolAndDescription") == 0) { + GMSD_SET(display, gt_display_mode_symbol_and_comment); + } + else { + GMSD_SET(display, gt_display_mode_symbol_and_name); + } + break; + case 7: if ( ! garmin_fs_merge_category(cdatastr, waypt)) { + warning(MYNAME ": Unable to convert category \"%s \"!\n", cdatastr); + } + break; + } +} + +unsigned char +garmin_fs_convert_category(const char *category_name, gbuint16 *category) +{ + int i; + int cat = 0; + + if ((case_ignore_strncmp(category_name, "Category ", 9) == 0) && + (1 == sscanf(category_name + 9, "%d", &i)) && + (i >= 1) && (i <= 16)) { + cat = (1 << --i); + } + else if (global_opts.inifile != NULL) { + for (i = 0; i < 16; i++) { + char *c; + char key[3]; + + snprintf(key, sizeof(key), "%d", i + 1); + c = inifile_readstr(global_opts.inifile, GMSD_SECTION_CATEGORIES, key); + if ((c != NULL) && (case_ignore_strcmp(c, category_name) == 0)) { + cat = (1 << i); + break; + } + } + } + if (cat == 0) { + return 0; + } + else { + *category = cat; + return 1; + } +} + +unsigned char +garmin_fs_merge_category(const char *category_name, waypoint *waypt) +{ + gbuint16 cat; + garmin_fs_t *gmsd; + + if (!garmin_fs_convert_category(category_name, &cat)) { + return 0; + } + + gmsd = GMSD_FIND(waypt); + cat = cat | ( GMSD_GET(category, 0) ); + + if (gmsd == NULL) { + gmsd = garmin_fs_alloc(-1); + fs_chain_add(&waypt->fs, (format_specific_data *) gmsd); + } + GMSD_SET(category, cat); + return 1; +} diff --git a/gpsbabel/garmin_fs.h b/gpsbabel/garmin_fs.h new file mode 100644 index 000000000..0c85b4419 --- /dev/null +++ b/gpsbabel/garmin_fs.h @@ -0,0 +1,120 @@ +/* + + Implementation of special data used by Garmin products. + + Copyright (C) 2006 Olaf Klein, o.b.klein@t-online.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#ifndef GARMIN_FS_H +#define GARMIN_FS_H + +#include +#include "defs.h" + +/* this order is used by most devices */ +/* typedef enum { + garmin_display_symbol_and_name = 0, + garmin_display_symbol_only = 1, + garmin_display_symbol_and_description = 2 +} garmin_display_t; +*/ + +/* macros */ + +#define GMSD_FIND(a) (garmin_fs_t *) fs_chain_find((a)->fs, FS_GMSD) + +/* GMSD_GET(a,b): a = any gmsd field, b = default value */ +#define GMSD_GET(a,b) ((gmsd) && (gmsd->flags.a)) ? (gmsd->a) : (b) + +/* GMSD_SET(a,b): a = numeric gmsd field, b = numeric source */ +#define GMSD_SET(a,b) if (gmsd) {gmsd->a = (b); gmsd->flags.a = 1; } + +/* GMSD_SETSTR(a,b): a = gmsd field, b = null terminated source */ +#define GMSD_SETSTR(a,b) if (gmsd && (b) && (b)[0]) { gmsd->a = xstrdup((b)); gmsd->flags.a = 1; } + +/* GMSD_SETNSTR(a,b,c): a = gmsd field, b = source, c = sizeof(source) */ +#define GMSD_SETNSTR(a,b,c) if (gmsd && (b) && (b)[0]) { gmsd->a = xstrndup((b),(c)); gmsd->flags.a = 1; } + +/* GMSD_GETNSTR(a,b,c): a = gmsd field, b = target, c = sizeof(target) */ +#define GMSD_GETNSTR(a,b,c) if (gmsd && gmsd->flags.a) strncpy((b),gmsd->a,(c)) + +typedef struct garmin_ilink_s { + int ref_count; + double lat, lon; + struct garmin_ilink_s *next; +} garmin_ilink_t; + +typedef struct { + unsigned int icon:1; + unsigned int wpt_class:1; + unsigned int display:1; + unsigned int category:1; + unsigned int depth:1; + unsigned int proximity:1; + unsigned int temperature:1; + unsigned int city:1; + unsigned int state:1; + unsigned int facility:1; + unsigned int cc:1; + unsigned int cross_road:1; + unsigned int addr:1; +} garmin_fs_flags_t; + +typedef struct garmin_fs_s +{ + format_specific_data fs; + garmin_fs_flags_t flags; + + int protocol; /* ... used by device (-1 is MapSource) */ + + gbint32 icon; + int wpt_class; + gbint32 display; + gbint16 category; + double depth; /* depth in meters */ + double proximity; /* proximity distance in meters */ + double temperature; + char *city; /* city name */ + char *facility; /* facility name */ + char *state; /* state */ + char *cc; /* country code */ + char *cross_road; /* Intersection road label */ + char *addr; /* address + number */ + garmin_ilink_t *ilinks; +} garmin_fs_t, *garmin_fs_p; + +garmin_fs_t *garmin_fs_alloc(const int protocol); +void garmin_fs_destroy(void *fs); +void garmin_fs_copy(garmin_fs_t **dest, garmin_fs_t *src); +char *garmin_fs_xstrdup(const char *src, size_t size); + +/* for GPX */ +void garmin_fs_xml_convert(const int base_tag, int tag, const char *cdatastr, waypoint *waypt); +void garmin_fs_xml_fprint(FILE *ofd, const waypoint *waypt); + +/* common garmin_fs utilities */ + +/* ..convert_category: returns 1=OK; 0=Unable to convert category */ +unsigned char garmin_fs_convert_category(const char *category_name, gbuint16 *category); + +/* ..merge_category: returns 1=OK; 0=Unable to convert category */ +unsigned char garmin_fs_merge_category(const char *category_name, waypoint *waypt); + +#define GMSD_SECTION_CATEGORIES "Garmin Categories" + +#endif -- 2.30.2